# ======================================================================
# Copyright CERFACS (March 2019)
# Contributor: Adrien Suau (adrien.suau@cerfacs.fr)
#
# This software is governed by the CeCILL-B license under French law and
# abiding  by the  rules of  distribution of free software. You can use,
# modify  and/or  redistribute  the  software  under  the  terms  of the
# CeCILL-B license as circulated by CEA, CNRS and INRIA at the following
# URL "http://www.cecill.info".
#
# As a counterpart to the access to  the source code and rights to copy,
# modify and  redistribute granted  by the  license, users  are provided
# only with a limited warranty and  the software's author, the holder of
# the economic rights,  and the  successive licensors  have only limited
# liability.
#
# In this respect, the user's attention is drawn to the risks associated
# with loading,  using, modifying and/or  developing or reproducing  the
# software by the user in light of its specific status of free software,
# that  may mean  that it  is complicated  to manipulate,  and that also
# therefore  means that  it is reserved for  developers and  experienced
# professionals having in-depth  computer knowledge. Users are therefore
# encouraged  to load and  test  the software's  suitability as  regards
# their  requirements  in  conditions  enabling  the  security  of their
# systems  and/or  data to be  ensured and,  more generally,  to use and
# operate it in the same conditions as regards security.
#
# The fact that you  are presently reading this  means that you have had
# knowledge of the CeCILL-B license and that you accept its terms.
# ======================================================================

import numpy

from qat.lang.AQASM.gates import AbstractGate, GateSignature

########################
# 1. Definition of U3
########################
_U3_signature = GateSignature("U3", [float, float, float], arity=1)


def _u3_generator(theta: float, phi: float, lambd: float):
    return numpy.array(
        [
            [numpy.cos(theta / 2), -numpy.exp(1.0j * lambd) * numpy.sin(theta / 2)],
            [
                numpy.exp(1.0j * phi) * numpy.sin(theta / 2),
                numpy.exp(1.0j * (phi + lambd)) * numpy.cos(theta / 2),
            ],
        ]
    )


_U3_signature.set_matrix_generator(_u3_generator)

U3 = AbstractGate(_U3_signature)

########################
# 2. Definition of U2
########################
_U2_signature = GateSignature("U2", [float, float], arity=1)


def _U2_generator(phi: float, lamb: float):
    return _u3_generator(numpy.pi / 2, phi, lamb)


_U2_signature.set_matrix_generator(_U2_generator)

U2 = AbstractGate(_U2_signature)

########################
# 3. Definition of U1
########################
_U1_signature = GateSignature("U1", [float], arity=1)


def _U1_generator(lamb: float):
    return _u3_generator(0, 0, lamb)


_U1_signature.set_matrix_generator(_U1_generator)

U1 = AbstractGate(_U1_signature)

########################
# 4. Definition of CX
########################
_CX_signature = GateSignature("CX", [], arity=2)


def _cx_generator():
    return numpy.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]])


_CX_signature.set_matrix_generator(_cx_generator)

CX = AbstractGate(_CX_signature)
